package com.gopay.common.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.CommunicationException;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

/**
 * 使用httpClient形式发送报文
 * 
 * HttpsTransport.java
 * 
 * @author WangfHongFei
 */
public class HttpsTransport {

	protected Log log = LogFactory.getLog(this.getClass());
	private String url = null;
	private int timeout = 10000;
	private int retryConnTimes = 5;
	private String sendEncoding = null;

	public HttpsTransport() {
	}

	public Object submit(Object obj) throws CommunicationException {
    	CloseableHttpClient httpClient = HttpClients.custom()
    			.setRetryHandler(new DefaultHttpRequestRetryHandler(retryConnTimes, false))
    			.build();
    	HttpPost method = new HttpPost(url);
    	
    	RequestConfig requestConfig = RequestConfig.custom()
    			.setSocketTimeout(timeout)
    			.setConnectTimeout(timeout)
    			.setConnectionRequestTimeout(timeout)
    			.build();
    	
        if (StringUtils.isNotEmpty(this.sendEncoding)) {
            method.setHeader(HTTP.CONTENT_ENCODING, sendEncoding);
        }
        method.setHeader(HTTP.USER_AGENT, "Rich Powered/1.0");
        
        method.setConfig(requestConfig);

		if (obj instanceof Map) {
			Map paraMap = (Map) obj;
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			for (Iterator iter = paraMap.keySet().iterator(); iter.hasNext();) {
				String key = (String) iter.next();
				nvps.add(new BasicNameValuePair(key, (String) paraMap.get(key)));
			}
			if (log.isInfoEnabled()) {
				log.info("Sent Data: " + paraMap);
			}
			
            try {
				method.setEntity(new UrlEncodedFormEntity(nvps));
			} catch (UnsupportedEncodingException e) {
				if (log.isErrorEnabled()) {
					log.error("Fatal transport error while try connect to [" + url + "]");
					log.error("Cause: " + e.getMessage());
	            }
				e.printStackTrace();
			}
		} else if (obj instanceof byte[]) {
			method.setEntity(new ByteArrayEntity((byte[]) obj));
			if (log.isInfoEnabled()) {log.info("Sent Data: " + new String((byte[]) obj));
			}
		} else {
			throw new IllegalArgumentException("submit(Object obj): obj should be Map or byte[]");
		}

		int statusCode = 0;
		String result = "";
		CloseableHttpResponse response = null;
		try {
			
        	response = httpClient.execute(method);
            statusCode = response.getStatusLine().getStatusCode();
            HttpEntity responseEntity = response.getEntity();
            result = EntityUtils.toString(responseEntity, sendEncoding);

            log.info("Received Data: "+ result);
		}  catch (IOException e) {
			log.fatal("Fatal transport error while try connect to [" + url+ "]");
			log.fatal("Cause: " + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (response != null) {
                    response.close();
                }
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (statusCode != HttpStatus.SC_OK) {
			if (log.isErrorEnabled()) {
				log.error("Answer from [" + url + "] status code: ["+ statusCode + "] response contents: ["+ result + "]");
			}
			throw new CommunicationException(String.valueOf(statusCode));
		}
		return result;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public void setRetryConnTimes(int retryConnTimes) {
		this.retryConnTimes = retryConnTimes;
	}

	public void setSendEncoding(String sendEncoding) {
		this.sendEncoding = sendEncoding;
	}

}
